昨天的 Day 8,我們成功讓 BMI API 從原本回傳一段文字,升級成回傳 JSON 格式。
例如:
{
"height": 162,
"weight": 50,
"bmi": 19.05
}
這樣不只讓資料更有結構,也方便未來前端網頁或其他程式讀取。
不過目前還有一個問題:
我們一直都是透過網址傳送資料,如果之後要輸入更多健康資訊,難道全部都要寫在網址裡面嗎?
例如:
/bmi?height=162&weight=50
只有兩個參數還算簡單。
但如果未來還想加入睡眠時間、飲水量、運動時間等資料,網址就會變得越來越長。
所以今天決定學習另一種傳送資料的方式:
使用 HTTP POST 搭配 @RequestBody,讓 Spring Boot 直接接收 JSON 格式的資料!
前幾天建立 API 時,我們一直使用:
@GetMapping
例如:
@GetMapping("/bmi")
這代表 API 會處理 HTTP GET Request。
不過 HTTP 其實不只有 GET,還有其他常見的 Method。
| Method | 常見用途 |
|---|---|
| GET | 取得資料 |
| POST | 提交資料或建立資源 |
| PUT | 更新或取代資源 |
| PATCH | 部分更新資料 |
| DELETE | 刪除資料 |
例如未來智慧健康助理可能會有:
GET /health-records
取得健康紀錄。
POST /health-records
新增健康紀錄。
DELETE /health-records/1
刪除編號為 1 的健康紀錄。
當然,這些目前都還只是規劃中的功能。
今天先從 POST 開始!
之前使用 GET 時,會把資料放在網址的 Query Parameters 裡。
例如:
http://localhost:8080/bmi?height=162&weight=50
Spring Boot 透過:
@RequestParam
取得資料。
但是 POST 可以把資料放在 HTTP Request Body 裡面。
例如:
{
"height": 162,
"weight": 50
}
這樣就不需要把每個欄位都放在網址中。
簡單比較:
| 比較項目 | GET | POST |
|---|---|---|
| 常見用途 | 讀取資料 | 提交資料 |
| 資料傳遞 | 常使用網址參數 | 常使用 Request Body |
| Spring Boot | @GetMapping |
@PostMapping |
| 接收資料 | @RequestParam |
@RequestBody |
| 瀏覽器直接測試 | 較方便 | 通常需要 API 測試工具 |
不過要注意,POST 並不代表資料會自動加密。
如果涉及個人健康資訊,仍然需要 HTTPS、身分驗證及適當的資料保護措施。
今天最重要的新東西就是:
@RequestBody
它可以讓 Spring Boot 讀取 HTTP Request Body,並將其中的 JSON 資料轉換成 Java 可以使用的物件。
例如使用者傳送:
{
"height": 162,
"weight": 50
}
Spring Boot 就可以將這些資料轉換成 Java 物件,再交給程式進行處理。
整個流程大概是:
使用者
↓
發送 POST Request
↓
Request Body(JSON)
↓
Spring Boot
↓
@RequestBody
↓
Java 物件
↓
進行資料處理
↓
回傳結果
這就是今天要完成的功能。
前幾天都是直接在 Controller 裡面使用:
@RequestParam double height
但是今天要接收 JSON,因此可以先建立一個 Java Class,用來表示使用者傳入的資料。
建立:
HealthRequest.java
程式如下:
public class HealthRequest {
private double height;
private double weight;
public HealthRequest() {
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
}
這裡使用了 Java 的封裝概念。
我們先將:
private double height;
private double weight;
設定為 private。
再透過 Getter 和 Setter 讀取或修改資料。
例如:
request.getHeight()
就可以取得身高。
而:
request.getWeight()
就可以取得體重。
Spring Boot 在常見的 Jackson JSON 設定下,可以利用這個類別的無參數建構子及 Setter,將 JSON 資料轉換成 HealthRequest 物件。
接下來建立:
HealthController.java
今天先做一個簡單的 API,讓使用者傳入身高與體重,然後回傳 BMI。
完整程式:
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class HealthController {
@PostMapping("/health/bmi")
public Map<String, Object> calculateBMI(
@RequestBody HealthRequest request) {
Map<String, Object> result = new HashMap<>();
double height = request.getHeight();
double weight = request.getWeight();
if (!Double.isFinite(height) ||
!Double.isFinite(weight) ||
height <= 0 || weight <= 0) {
result.put("error",
"Height and weight must be positive numbers.");
return result;
}
double heightInMeters = height / 100;
double bmi = weight / (heightInMeters * heightInMeters);
if (!Double.isFinite(bmi)) {
result.put("error", "Unable to calculate BMI.");
return result;
}
double roundedBmi = Math.round(bmi * 100.0) / 100.0;
result.put("height", height);
result.put("weight", weight);
result.put("bmi", roundedBmi);
return result;
}
}
這次使用的路徑是:
POST /health/bmi
因此不會和昨天的:
GET /bmi
產生衝突。
今天第一個新 Annotation:
@PostMapping("/health/bmi")
它代表當 Spring Boot 收到:
POST /health/bmi
就會執行對應的 Method。
這和之前的:
@GetMapping("/bmi")
概念很接近。
只是兩者處理的 HTTP Method 不同。
目前可以先記成:
@GetMapping → 處理 GET
@PostMapping → 處理 POST
接下來是今天最重要的地方:
@RequestBody HealthRequest request
它代表 Spring Boot 會將 Request Body 中的 JSON 資料,轉換成 HealthRequest 物件。
例如傳入:
{
"height": 162,
"weight": 50
}
程式就可以透過:
double height = request.getHeight();
double weight = request.getWeight();
取得資料。
這樣就不需要像之前一樣,在網址中寫:
?height=162&weight=50
而是可以直接傳送 JSON。
前幾天都是直接在瀏覽器網址列輸入網址。
但今天使用 POST,因此不能只靠在網址列輸入路徑來測試。
我們可以使用 Postman 等 API 測試工具。
將 HTTP Method 設定成:
POST
http://localhost:8080/health/bmi
選擇:
Body → raw → JSON
輸入:
{
"height": 162,
"weight": 50
}
並確認 Request Header 包含:
Content-Type: application/json
按下 Send。
如果程式正常執行,預期會收到:
{
"height": 162.0,
"weight": 50.0,
"bmi": 19.05
}
這樣就代表 Spring Boot 成功接收 JSON,並完成 BMI 計算!
回顧昨天的寫法:
@GetMapping("/bmi")
public Map<String, Object> calculateBMI(
@RequestParam double height,
@RequestParam double weight) {
// BMI 計算
}
今天改成:
@PostMapping("/health/bmi")
public Map<String, Object> calculateBMI(
@RequestBody HealthRequest request) {
// BMI 計算
}
最大的差別就是資料的接收方式。
GET /bmi?height=162&weight=50
↓
@RequestParam
↓
取得 height、weight
POST /health/bmi
↓
Request Body
↓
JSON
↓
@RequestBody
↓
HealthRequest 物件
雖然最後都是計算 BMI,但今天的方式更適合接收包含多個欄位的資料。
現在 HealthRequest 只有:
private double height;
private double weight;
但之後可以慢慢擴充。
例如:
private double sleepHours;
private int waterIntake;
private int exerciseMinutes;
未來就可以接收:
{
"height": 162,
"weight": 50,
"sleepHours": 7,
"waterIntake": 1500,
"exerciseMinutes": 30
}
這樣使用者就可以一次提交多種健康資料。
不過目前我們還沒有建立資料庫,所以這些資料只會在這次 Request 中被處理,並不會自動儲存下來。
等之後學到資料庫,再慢慢加入健康紀錄的儲存功能。
第一次使用 POST 時,可能會遇到一些問題。
可能原因:
可能是使用 GET 去呼叫只支援 POST 的 API。
例如直接在瀏覽器輸入:
http://localhost:8080/health/bmi
瀏覽器通常會發送 GET Request,但我們設定的是:
@PostMapping
所以就可能出現 405。
可能原因:
可能是沒有正確設定:
Content-Type: application/json
因此 Spring Boot 無法依照預期的格式處理資料。
遇到這些問題時,可以先檢查 HTTP Method、URL、Header 和 Body。
Day 7:
接收網址參數
↓
計算 BMI
↓
回傳文字
Day 8:
接收網址參數
↓
計算 BMI
↓
回傳 JSON
Day 9:
接收 POST Request
↓
讀取 JSON
↓
轉換成 Java 物件
↓
計算 BMI
↓
回傳 JSON
今天最大的進步,就是系統已經可以同時處理 JSON 輸入與 JSON 輸出。
這也讓我們離未來的 AI API 串接又更近了一步!
今天第一次使用:
@PostMapping
以及:
@RequestBody
讓 Spring Boot 不只能透過網址參數取得資料,也能直接接收 JSON。
今天學到的重點包括:
@PostMapping 的用途@RequestBody 如何接收 JSONHealthRequest Java 類別現在我們的智慧健康助理已經可以:
接收 JSON → 轉換成 Java 物件 → 處理健康資料 → 回傳 JSON。
雖然目前還是在做 BMI,但今天學到的資料傳遞方式,未來也能應用在健康紀錄與 AI 功能中。
目前我們把接收 Request 和 BMI 計算邏輯都寫在 Controller 裡面。
雖然程式可以正常運作,但如果未來要加入睡眠、飲水、運動等功能,Controller 可能會越來越長。
所以下一篇準備認識:
讓智慧健康助理不只是功能越來越多,程式結構也能越來越清楚!